#include "Rule.h"
#include "util/StringUtils.h"

namespace parser {

double stringToDouble(std::string str) throw (InvalidDataException);

// Rule
Rule::Rule(char dataSeparator) {
	this->separator = dataSeparator; // caracter separador de datos
	this->k = 0; // cantidad de valores cargados
}
Rule::~Rule() {
	delete this->parsedData;
}
/* Devuelve el separador de datos */
char Rule::getDataSeparator() {
	return this->separator;
}

ParsedData* Rule::getParsedData(bool clearData) throw (InvalidDataException) {
	ParsedData* ret = this->parsedData;
	bool dataUnsuccessfullyParsed = this->k < this->n;
	if (clearData) {
		this->resetParsedData();
	}
	if (dataUnsuccessfullyParsed) {
		if (clearData) {
			ret->~ParsedData();
		}
		throw(InvalidDataException("Faltan datos para ser procesados."));
	}
	return ret;
}
void Rule::resetParsedData() {
	this->k = 0;
	this->parsedData = this->buildNewParsedData();
}

void Rule::discardCurrentParsedData() {
	ParsedData* ret = this->parsedData;
	this->resetParsedData();
	delete ret;
}
// VertexRule

VertexRule::VertexRule(char dataSeparator) :
	Rule(dataSeparator) {
	this->n = 3; // cantidad de valores para un vertice
	this->parsedData = this->buildNewParsedData();
}

VertexRule::~VertexRule() {
}

ParsedData* VertexRule::buildNewParsedData() {
	return new VertexParsedData();
}
VertexRule* VertexRule::addValue(std::string val) throw (InvalidDataException) {
	if (this->k >= this->n) {
		this->parsedData->addWarning(
				"Se intento agregar un dato de mas (dato extra \"" + val
						+ "\"), este va a ser ignorado.");
	} else {
		try {
			switch (this->k) {
			case 0:
				((VertexParsedData*) (this->parsedData))->setId(val);
				break;
			case 1:
				((VertexParsedData*) (this->parsedData))->setX(
						util::stringToDouble(val));
				break;
			case 2:
				((VertexParsedData*) (this->parsedData))->setY(
						util::stringToDouble(val));
				break;
			default:
				throw(InvalidDataException(
						"No hay manera de que se pueda producir este error."));
			}
		} catch (InvalidDataException& e) {
			if (this->isImportantField(k)) {
				throw ;
			} else {
				this->parsedData->addWarning("Error al agregar el valor \"" + val
						+ "\" para el campo " + util::intToString(k)
						+ " del vertice \""
						+ ((VertexParsedData*) (this->parsedData))->getId()
						+ "\", se va a utilizar el valor por defecto: " + e.getMessage());
			}
		}
		k++;
	}
	return this;
}

bool VertexRule::isImportantField(int k) {
	return (k == 0);
}

// EdgeRule

EdgeRule::EdgeRule(char dataSeparator) :
Rule(dataSeparator) {
	this->n = 5; // cantidad de valores para una arista
	this->parsedData = this->buildNewParsedData();
}

EdgeRule::~EdgeRule() {
}

ParsedData* EdgeRule::buildNewParsedData() {
	return new EdgeParsedData();
}

EdgeRule* EdgeRule::addValue(std::string val) throw (InvalidDataException) {
	if (this->k >= this->n) {
		this->parsedData->addWarning(
				"Se intento agregar un dato de mas (dato extra \"" + val
				+ "\"), este va a ser ignorado.");
	} else {
		try {
			switch (this->k) {
				case 0:
				((EdgeParsedData*) (this->parsedData))->setId(val);
				break;
				case 1:
				((EdgeParsedData*) (this->parsedData))->setIdO(val);
				break;
				case 2:
				((EdgeParsedData*) (this->parsedData))->setIdD(val);
				break;
				case 3:
				((EdgeParsedData*) (this->parsedData))->setLength(util::stringToDouble(val));
				break;
				case 4:
				((EdgeParsedData*) (this->parsedData))->setMaxSpeed(util::stringToDouble(val));
				break;
				default:
				throw(InvalidDataException(
								"No hay manera de que se pueda producir este error."));
			}
		} catch (InvalidDataException& e) {
			if (this->isImportantField(k)) {
				throw;
			} else {
				this->parsedData->addWarning("Error al agregar el valor \""
						+ val + "\" para el campo " + util::intToString(k)
						+ " de la arista \""
						+ ((EdgeParsedData*) (this->parsedData))->getId()
						+ "\", se va a utilizar el valor por defecto: " + e.getMessage());
			}
		}
		k++;
	}
	return this;
}

bool EdgeRule::isImportantField(int k) {
	return ((k == 0) || (k == 1) || (k == 2));
}

}
; // end of namespace
